  using Microsoft.Win32;
  using System;
  using System.Runtime.InteropServices;
  using System.Runtime.Serialization;
  using System.Security.Permissions;
  using System.Text;
  using System.IO;
	namespace Common.Shared.IO {


  public class LogicalDriveInfo : IDisposable {
    private string _name = string.Empty;
    private char _letter;
    private long _freeBytesAvailable = 0;
    private long _totalNumberOfBytes = 0;
    private long _totalNumberOfFreeBytes = 0;
    private DriveType _driveType = DriveType.Unknown;
    private string _fileSystem = string.Empty;
    private bool _isReady = false;
    private int _serialNumber = 0;
    private int _maxComponentLength = 0;
    private int _fileSystemFlags = 0;
    private string _volumeName = string.Empty;
    private DirectoryInfo _rootDirectory = null;

    #region Private API Declarations
    /// <summary>
    /// The GetDriveType function determines whether a disk drive is a removable, 
    /// fixed, CD-ROM, RAM disk, or network drive.
    /// </summary>
    /// <param name="rootPathName">
    /// A pointer to a null-terminated string that specifies the root directory 
    /// and returns information about the disk.
    /// 
    /// A trailing backslash is required. If this parameter is <b>null</b>, the 
    /// function uses the root of the current directory.
    /// </param>
    /// <returns>
    /// The return value specifies the type of drive, which can be one of the 
    /// following values.
    /// </returns>
    [DllImport ( "kernel32" )]
    private static extern uint GetDriveType ( string rootPathName );

    /// <summary>
    /// The GetVolumeInformation function retrieves information about a file system 
    /// and volume that have a specified root directory.
    /// </summary>
    /// <param name="rootPathName">The root drive string, such as "C:\"</param>
    /// <param name="volumeNameBuffer">A buffer for storing the volume name string.</param>
    /// <param name="volumeNameSize">An integer indicating the size of the buffer.</param>
    /// <param name="volumeSerialNumber">A long value containing the drive serial number.</param>
    /// <param name="maximumComponentLength"></param>
    /// <param name="fileSystemFlags">A long value containing the file system flags.</param>
    /// <param name="fileSystemNameBuffer">A buffer for storing the file system name string.</param>
    /// <param name="fileSystemNameSize">An integer indicating the size of the buffer.</param>
    /// <returns></returns>
    [DllImport ( "kernel32" )]
    private static extern bool GetVolumeInformation (
      string rootPathName,
      StringBuilder volumeNameBuffer,
      int volumeNameSize,
      ref int volumeSerialNumber,
      ref int maximumComponentLength,
      ref int fileSystemFlags,
      StringBuilder fileSystemNameBuffer,
      uint fileSystemNameSize );

    /// <summary>
    /// Gets the disk free space.
    /// </summary>
    /// <param name="rootDirectoryName">Name of the root directory.</param>
    /// <param name="freeBytesAvailable">The free bytes available.</param>
    /// <param name="totalNumberOfBytes">The total number of bytes.</param>
    /// <param name="totalNumberOfFreeBytes">The total number of free bytes.</param>
    /// <returns></returns>
    [DllImport ( "kernel32" )]
    private static extern bool GetDiskFreeSpaceEx (
      string rootDirectoryName,
      ref long freeBytesAvailable,
      ref long totalNumberOfBytes,
      ref long totalNumberOfFreeBytes
      );

    [DllImport ( "kernel32" )]
    private static extern bool SetVolumeLabel ( string lpRootPathName, string lpVolumeName );

    #endregion
    
    
    public LogicalDriveInfo ( char driveLetter ) {
      if ( !char.IsLetter(driveLetter) ) {
        throw new ArgumentException ( "driveLetter is not a valid drive letter." );
      }
      this._letter = driveLetter;
      this._name = string.Format ( "{0}{1}{2}", driveLetter, Path.VolumeSeparatorChar, Path.DirectorySeparatorChar );
      this._rootDirectory = new DirectoryInfo ( this._name );

      string drive = string.Format ( "{0}{1}", driveLetter, Path.VolumeSeparatorChar );

      GetDiskFreeSpaceEx ( drive, ref _freeBytesAvailable,
        ref _totalNumberOfBytes, ref _totalNumberOfFreeBytes );
			StringBuilder fsBuilder = new StringBuilder();
			StringBuilder volBuilder = new StringBuilder();
      bool result = GetVolumeInformation ( _name, volBuilder, 256, ref _serialNumber, ref _maxComponentLength, ref _fileSystemFlags,
        fsBuilder, 256 );

      if ( result ) {
        this._fileSystem = fsBuilder.ToString ( );
        this._volumeName = volBuilder.ToString ( );
      }

      _driveType = (DriveType)GetDriveType ( drive );
      string path = _name + '.';
      new FileIOPermission ( FileIOPermissionAccess.PathDiscovery, path ).Demand ( );
    }

    public static LogicalDriveInfo[] GetDrives ( ) {
      string[] logicalDrives = Directory.GetLogicalDrives ( );
      LogicalDriveInfo[] infoArray = new LogicalDriveInfo[ logicalDrives.Length ];
      for ( int i = 0; i < logicalDrives.Length; i++ ) {
        infoArray[ i ] = new LogicalDriveInfo ( logicalDrives[ i ][0] );
      }
      return infoArray;
    }

    /// <summary>
    /// Gets the letter.
    /// </summary>
    /// <value>The letter.</value>
    public char Letter { get { return this._letter; } }

    public override string ToString ( ) {
      return this.Name;
    }

    public long AvailableFreeSpace {
      get {
        return _freeBytesAvailable;
      }
    }

    public string DriveFormat {
      get {
        return this._fileSystem;
      }
    }

    public DriveType DriveType {
      get {
        return _driveType;
      }
    }

    public bool IsReady {
      get {
        try {
          return Directory.Exists ( this.Name );
        } catch {
          return false;
        }
      }
    }

    public string Name {
      get {
        return this._name;
      }
    }

    public DirectoryInfo RootDirectory {
      get {
        return this._rootDirectory;
      }
    }

    public long TotalFreeSpace {
      get {
        return _totalNumberOfFreeBytes;
      }
    }

    public long TotalSize {
      get {
        return _totalNumberOfBytes;
      }
    }

    public string VolumeLabel {
      get {
        return this._volumeName;
      }
      set {
        bool result = SetVolumeLabel ( this.Name, value );
        if ( result )
          this._volumeName = value;
      }
    }

    public bool HasFilesOrFolders {
      get {
        try {
          DirectoryInfo[] dirs = this.RootDirectory.GetDirectories ( );
          FileInfo[] files = this.RootDirectory.GetFiles ( );
          return dirs.Length > 0 || files.Length > 0;
        } catch {
          return false;
        }
      }
    }

    #region IDisposable Members

    public void Dispose ( ) {
      throw new Exception ( "The method or operation is not implemented." );
    }

    #endregion
  }
}

